/**
 * @author Javier Guaje <jrguajeg@gmail.com>
 */

package co.edu.unal.satacredito.database.dao;

import co.edu.unal.satacredito.database.constants.TransactionConstants;
import co.edu.unal.satacredito.database.entity.FileLog;
import co.edu.unal.satacredito.database.entity.Transaction;
import co.edu.unal.satacredito.database.exception.UnreachableHostException;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.query.Query;
import com.mongodb.BasicDBObject;
import java.util.Date;
import java.util.List;
import org.bson.types.ObjectId;

public class ReportMongoDao {
    
    private static final String BRAND = "brand";
    private static final String ESTABLISHMENT = "establishment";
    
    private static final String FILE_ID = "fileId";
    
    private static final String VALIDATION_RESULT = "validationResult";
    private static final String VALIDATION_ISSUE = "validationIssue";
    private static final String READ_STATE = "readState";
    
    private static final String PURCHASE_DATE = "purchaseDate";
    
    private static final String FRANCHISE = "franchise";
    
    private static final String PURCHASE_AMOUNT = "purchaseAmount";
    
    private Datastore mDs;
    
    public ReportMongoDao(Datastore datastore) {
        this.mDs = datastore;
    }
    
    public List<Transaction> findApprovedByDateRangeAndBrand(Date initDate, Date endDate,
            ObjectId idBrand) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        return query.asList();
    }
    
    public List<Transaction> findApprovedByDateRangeAndEstablishment(Date initDate, Date endDate,
            ObjectId idEstablishment) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        return query.asList();
    }
    
    public List<Transaction> findApprovedByDateRangeAndBrandAndFranchise(Date initDate, Date endDate,
            ObjectId idBrand, ObjectId idFranchise) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        return query.asList();
    }
    
    public List<Transaction> findApprovedByDateRangeAndEstablishmentAndFranchise(Date initDate, Date endDate,
            ObjectId idEstablishment, ObjectId idFranchise) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        return query.asList();
    }
    
    public List<Transaction> findApprovedByDateRangeAndBrandAndAmountRange(Date initDate, Date endDate,
            ObjectId idBrand, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }
    
    public List<Transaction> findApprovedByDateRangeAndEstablishmentAndAmountRange(Date initDate, Date endDate,
            ObjectId idEstablishment, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }
    
    public List<Transaction> findApprovedByDateRangeAndBrandAndFranchiseAndAmountRange(Date initDate, Date endDate,
            ObjectId idBrand, ObjectId idFranchise, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }
    
    public List<Transaction> findApprovedByDateRangeAndEstablishmentAndFranchiseAndAmountRange(Date initDate, Date endDate,
            ObjectId idEstablishment, ObjectId idFranchise, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_APPROVED);
        query.field(VALIDATION_ISSUE).equal(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndBrand(Date initDate, Date endDate,
            ObjectId idBrand) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndEstablishment(Date initDate, Date endDate,
            ObjectId idEstablishment) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndBrandAndFranchise(Date initDate, Date endDate,
            ObjectId idBrand, ObjectId idFranchise) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndEstablishmentAndFranchise(Date initDate, Date endDate,
            ObjectId idEstablishment, ObjectId idFranchise) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndBrandAndAmountRange(Date initDate, Date endDate,
            ObjectId idBrand, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndEstablishmentAndAmountRange(Date initDate, Date endDate,
            ObjectId idEstablishment, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndBrandAndFranchiseAndAmountRange(Date initDate, Date endDate,
            ObjectId idBrand, ObjectId idFranchise, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(BRAND, idBrand));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }
    
    public List<Transaction> findFailedByDateRangeAndEstablishmentAndFranchiseAndAmountRange(Date initDate, Date endDate,
            ObjectId idEstablishment, ObjectId idFranchise, long initAmount, long endAmount) throws UnreachableHostException {
        List<ObjectId> fileIds = mDs.getCollection(FileLog.class).distinct(FILE_ID,
                                                                           new BasicDBObject(ESTABLISHMENT, idEstablishment));
        Query<Transaction> query = mDs.find(Transaction.class);
        query.field(FILE_ID).in(fileIds);
        query.field(VALIDATION_RESULT).equal(TransactionConstants.RESULT_FAILED);
        query.field(VALIDATION_ISSUE).notEqual(TransactionConstants.ISSUE_NOT);
        query.field(READ_STATE).equal(TransactionConstants.READ_SEMANTIC);
        query.field(PURCHASE_DATE).greaterThanOrEq(initDate);
        query.field(PURCHASE_DATE).lessThanOrEq(endDate);
        query.field(FRANCHISE).equal(idFranchise);
        query.field(PURCHASE_AMOUNT).greaterThanOrEq(initAmount);
        query.field(PURCHASE_AMOUNT).lessThanOrEq(endAmount);
        return query.asList();
    }    
}